﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using TXTD.Admin.Data.Entitys.System;
using TXTD.Admin.Framework.CostomException;
using TXTD.Admin.Framework.Encryption;
using TXTD.Admin.Framework.ExpressionCore;
using TXTD.Admin.Framework.Reflection;
using TXTD.Admin.Interface.System;
using TXTD.Admin.Model.Core;
using TXTD.Admin.Model.Modules.System;
using TXTD.Admin.Model.Paging;
using TXTD.Admin.Service.Utilitys.Jwt;

namespace TXTD.Admin.Service.System
{
    public class SysUserService : BaseService<SysUser>, ISysUserService
    {
        private JwtHelper jwtHelper;
        private ISysUserRefreshTokenService userRefreshTokenService;
        /// <summary>
        /// 构造函数 必须这么写 需要 DbContext dbContext, IHttpContextAccessor httpContextAccessor
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="httpContextAccessor"></param>
        public SysUserService(DbContext dbContext, IHttpContextAccessor httpContextAccessor, JwtHelper _jwtHelper, ISysUserRefreshTokenService _userRefreshTokenService) : base(dbContext, httpContextAccessor)
        {
            this.jwtHelper = _jwtHelper;
            this.userRefreshTokenService = _userRefreshTokenService;
        }
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <returns></returns>
        public PageResult<SysUserModel> GetPageList(SysUser model)
        {
            #region 动态凭借查询条件
            ExpressionHelper<SysUser> expressionHelper = new();
            expressionHelper.Contains(nameof(SysUser.UserCode), model.UserCode);
            expressionHelper.Contains(nameof(SysUser.UserName), model.UserName);
            Expression<Func<SysUser, bool>> where = expressionHelper.GetExpression();
            #endregion
            PageResult<SysUserModel> pageResult = QueryPageList<SysUserModel>(where);
            if (pageResult != null && pageResult.List != null)
            {
                //绑定用户角色
                foreach (SysUserModel item in pageResult.List)
                {
                    item.RoleIds = db.Set<SysUserRole>().Where(t => t.UserId == item.UserId).Select(t => t.RoleId).ToList();
                }
            }
            return pageResult;
        }
        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int Add(SysUser model)
        {
            model.PasswordKey = Guid.NewGuid().ToString("N").Substring(3, 16);
            model.Password = Md5Utils.GetDoubleMd5String(model.PasswordKey + model.Password);
            int count = InsertModel(model);
            if (count > 0)
            {
                //保存用户角色
                count += SaveUserRole(model);
            }
            return count;
        }

        /// <summary>
        /// 修改数据
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int Update(SysUser model)
        {
            CheckEdit(model.UserId);
            int count = UpdateModel(model, model.UserId);
            if (count > 0)
            {
                //保存用户角色
                count += SaveUserRole(model);
            }
            return count;
        }

        /// <summary>
        /// 保存用户角色
        /// </summary>
        /// <param name="model"></param>
        /// <exception cref="NotImplementedException"></exception>
        private int SaveUserRole(SysUser model)
        {
            //先删除用户的角色
            db.Set<SysUserRole>().RemoveRange(db.Set<SysUserRole>().Where(t => t.UserId == model.UserId));
            //再保存角色的菜单
            if (model.RoleIds != null)
            {
                foreach (var roleId in model.RoleIds)
                {
                    db.Set<SysUserRole>().Add(new SysUserRole()
                    {
                        UserId = model.UserId,
                        RoleId = roleId
                    });
                }
            }
            return db.SaveChanges() + 1;
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>

        public int DeleteById(string id)
        {
            CheckEdit(id);
            return RemoveById(id);
        }
        /// <summary>
        /// 修改启用状态
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int UpdateEnabled(SysUser model)
        {
            return Update(new SysUser()
            {
                UserId = model.UserId,
                Enabled = model.Enabled
            });
        }
        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int ResetPassword(SysUser model)
        {
            string PasswordKey = Guid.NewGuid().ToString("N").Substring(3, 16);
            string Password = Md5Utils.GetDoubleMd5String(PasswordKey + model.Password);
            return Update(new SysUser()
            {
                UserId = model.UserId,
                PasswordKey = PasswordKey,
                Password = Password
            });
        }
        private void CheckEdit(string UserId)
        {
            SysUser user = GetModelById(UserId);
            if (user.UserId == "8D13842CAC3BC844FCB1957F74BB8762" || user.UserCode == "admin")
            {
                throw new BusinessMessageException("超级管理员无法修改或删除");
            }
        }
        /// <summary>
        /// 当前登录用户
        /// </summary>
        /// <returns></returns>
        public object GetUserInfo()
        {
            if (LoginUser == null) return null;
            return new
            {
                UserCode = LoginUser.UserCode,
                UserName = LoginUser.UserName,
                RealName = LoginUser.RealName,
                //权限
                Permissions = new List<string>() { "1", "2" }
            };
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public ResultModel Login(LoginModel user)
        {
            ResultModel resultModel = new ResultModel();
            var _user = db.Set<SysUser>().Where(t => t.UserCode == user.UserCode).FirstOrDefault();
            if (_user != null)
            {
                string Password = Md5Utils.GetDoubleMd5String(_user.PasswordKey + user.Password);
                if (_user.Password == Password)
                {
                    if (_user.Enabled)
                    {
                        ResultTokenModel resultToken = GetToken(_user);
                        Dictionary<string, object> keyValues = new()
                        {
                            { "resultToken", resultToken },
                            {
                                "user",
                                new
                                {
                                    _user.UserCode,
                                    _user.UserName
                                }
                            }
                        };



                        resultModel.Success = true;
                        resultModel.Message = "登录成功";
                        resultModel.Result = keyValues;
                    }
                    else
                    {
                        resultModel.Success = false;
                        resultModel.Message = "登录失败：用户已禁用，请联系管理员";
                    }
                }
                else
                {
                    resultModel.Success = false;
                    resultModel.Message = "登录失败：用户密码错误";
                }
            }
            else
            {
                resultModel.Success = false;
                resultModel.Message = "登录失败：用户账号不存在";
            }
            return resultModel;
        }
        /// <summary>
        /// 获取token
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        private ResultTokenModel GetToken(SysUser user)
        {
            ResultTokenModel resultToken = jwtHelper.CreateToken(user);

            userRefreshTokenService.Add(new SysUserRefreshToken()
            {
                UserId = user.UserId,
                Token = resultToken.RefreshToken,
                CreatedBy = "登录"
            });

            return resultToken;
        }
        /// <summary>
        /// 刷新token
        /// </summary>
        /// <param name="resultToken"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public ResultTokenModel RefreshToken(ResultTokenModel resultToken)
        {
            var TokenClaimsPrincipal = jwtHelper.GetClaimsPrincipalByToken(resultToken.Token);
            var RefreshTokenClaimsPrincipal = jwtHelper.GetClaimsPrincipalByToken(resultToken.RefreshToken);

            //获取token过期时间
            var tokenExpiryDateUnix = long.Parse(TokenClaimsPrincipal.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Exp).Value);
            DateTime expiryDateTimeUtc = UnixTimeToDateTime(tokenExpiryDateUnix).AddMinutes(-5);

            //获取刷新token的过期时间
            var resultTokenExpiryDateUnix = long.Parse(RefreshTokenClaimsPrincipal.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Exp).Value);
            DateTime resultTokenExpiryDateTimeUtc = UnixTimeToDateTime(resultTokenExpiryDateUnix);
            DateTime nowDate = DateTime.Now;

            //token已过期
            if (expiryDateTimeUtc < nowDate)
            {
                //刷新token还未过期
                if (resultTokenExpiryDateTimeUtc > nowDate)
                {
                    SysUserRefreshToken userRefreshToken = userRefreshTokenService.GetModelByToken(resultToken.RefreshToken);
                    if (userRefreshToken != null && !userRefreshToken.IsUsed)
                    {
                        //获取用户id
                        string UserId = TokenClaimsPrincipal.Claims.FirstOrDefault(t => t.Type == "UserId").Value;
                        SysUser user = GetModelById(UserId);
                        if (user != null)
                        {
                            userRefreshToken.IsUsed = true;
                            userRefreshTokenService.Update(userRefreshToken);

                            return GetToken(user);
                        }
                    }
                }
            }
            return null;
        }


        public static DateTime UnixTimeToDateTime(long time)
        {
            return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddSeconds(time);
        }
    }
}